迈出云原生重要一步 — Dubbo 3 应用级服务发现
喜欢就关注我们吧!
Dubbo 与开源中国共同策划【Dubbo 云原生之路】系列文章,和大家一起回顾 Apache Dubbo 社区的发展。这是系列第二篇。系列文章主要涵盖 Dubbo 技术解读、社区运营、应用案例解析三大部分。
在这里,我们也向所有的 Dubbo 用户和开发者发出投稿邀请,如果你正在使用 Dubbo,或是正在为 Dubbo 贡献力量,欢迎和我们分享你的开发使用经验,优质文章也会收录进【Dubbo 云原生之路】系列。
投稿地址:xuyijun@oschina.cn
本文作者:刘军
花名陆龟,Github 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。
一、服务发现(Service Discovery)概述
从 Internet 刚开始兴起,如何动态感知后端服务的地址变化就是一个必须要面对的问题,为此人们定义了 DNS 协议
基于此协议,调用方只需要记住由固定字符串组成的域名,就能轻松完成对后端服务的访问,而不用担心流量最终会访问到哪些机器 IP,因为有代理组件会基于 DNS 地址解析后的地址列表,将流量透明的、均匀的分发到不同的后端机器上。
在使用微服务构建复杂的分布式系统时,如何感知 backend 服务实例的动态上下线,也是微服务框架最需要关心并解决的问题之一。
业界将这个问题称之为 - 微服务的地址发现(Service Discovery),业界比较有代表性的微服务框架如 SpringCloud、Microservices、Dubbo 等都抽象了强大的动态地址发现能力,并且为了满足微服务业务场景的需求,绝大多数框架的地址发现都是基于自己设计的一套机制来实现
因此在能力、灵活性上都要比传统 DNS 丰富得多。如 SpringCloud 中常用的 Eureka, Dubbo 中常用的 Zookeeper、Nacos 等,这些注册中心实现不止能够传递地址(IP + Port),还包括一些微服务的 Metadata 信息,如实例序列化类型、实例方法列表、各个方法级的定制化配置等。
下图是微服务中 Service Discovery 的基本工作原理图,微服务体系中的实例大概可分为三种角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。
而不同框架实现间最主要的区别就体现在注册中心数据的组织:地址如何组织、以什么粒度组织、除地址外还同步哪些数据?
我们今天这篇文章就是围绕这三个角色展开,重点看下 Dubbo 中对于服务发现方案的设计,包括之前老的服务发现方案的优势和缺点,以及 Dubbo 3.0 中正在设计、开发中的全新的面向应用粒度的地址发现方案,我们期待这个新的方案能做到:
支持几十万/上百万级集群实例的地址发现 与不同的微服务体系(如 Spring Cloud)实现在地址发现层面的互通
二、Dubbo 地址发现机制解析
我们先以一个 DEMO 应用为例,来快速的看一下 Dubbo “接口粒度”服务发现与“应用粒度”服务发现体现出来的区别。这里我们重点关注 Provider 实例是如何向注册中心注册的,并且,为了体现注册中心数据量变化,我们观察的是两个 Provider 实例的场景。应用 DEMO 提供的服务列表如下:<dubbo:service interface="org.apache.dubbo.samples.basic.api.GreetingService" ref="greetingService"/>
2.1 “接口粒度” 服务发现
192.168.0.103 实例注册的数据:
dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266
dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816
192.168.0.104 实例注册的数据:
dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266
dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816
2.2 “应用粒度” 服务发现
192.168.0.103 实例数据:
{
"name": "demo-provider",
"id": "192.168.0.103:20880",
"address": "192.168.0.103",
"port": 20880,
"metadata": {
"dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"dubbo.metadata.storage-type": "local",
"dubbo.revision": "6785535733750099598"
},
"time": 1583461240877
}
192.168.0.104 实例数据:
{
"name": "demo-provider",
"id": "192.168.0.104:20880",
"address": "192.168.0.104",
"port": 20880,
"metadata": {
"dubbo.endpoints": "[{"port":20880,"protocol":"dubbo"}]",
"dubbo.metadata.storage-type": "local",
"dubbo.revision": "7829635812370099387"
},
"time": 1583461240947
}
对比以上两种不同粒度的服务发现模式,从 “接口粒度” 升级到 “应用粒度” 后我们可以总结出最大的区别是:注册中心数据量不再与接口数成正比,不论应用提供有多少接口,注册中心只有一条实例数据。
那么接下来我们详细看下这个变化给 Dubbo 带来了哪些好处。
三、Dubbo 应用级服务发现的意义
我们先说结论,应用级服务发现给 Dubbo 带来以下优势:
与业界主流微服务模型对齐,比如 SpringCloud、Kubernetes Native Service 等 提升性能与可伸缩性。注册中心数据的重新组织(减少),能最大幅度的减轻注册中心的存储、推送压力,进而减少 Dubbo Consumer 侧的地址计算压力;集群规模也开始变得可预测、可评估(与 RPC 接口数量无关,只与实例部署规模相关)
3.1 对齐主流微服务模型
自动、透明的实例地址发现(负载均衡)是所有微服务框架需要解决的事情,这能让后端的部署结构对上游微服务透明,上游服务只需要从收到的地址列表中选取一个,发起调用就可以了。要实现以上目标,涉及两个关键点的自动同步:实例地址,服务消费方需要知道地址以建立链接 RPC 方法定义,服务消费方需要知道 RPC 服务的具体定义,不论服务类型是 rest 或 rmi 等
服务注册由平台接管,provider 不再需要关心服务注册 consumer 端服务发现将是 Dubbo 关注的重点,通过对接平台层的 API-Server、DNS 等,Dubbo client 可以通过一个 Service Name(通常对应到 Application Name)查询到一组 Endpoints(一组运行 provider 的 pod),通过将 Endpoints 映射到 Dubbo 内部地址列表,以驱动 Dubbo 内置的负载均衡机制工作
Service Name - > Application Name,Dubbo 应用和 Kubernetes 服务一一对应,对于微服务运维和建设环节透明,与开发阶段解耦
kind: Service
metadata:
name:provider-app-namespec:
selector:
app:provider-app-name
ports:
-protocol:TCP
port:
targetPort:9376
Service Name - > Dubbo RPC Service,Kubernetes 要维护调度的服务与应用内建 RPC 服务绑定,维护的服务数量变多
apiVersion: v1
kind: Service
metadata:
name: rpc-service-1
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-2
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-N
spec:
selector:
app: provider-app-name
ports: ##
...
3.2 更大规模的微服务集群 - 解决性能瓶颈
这部分涉及到和注册中心、配置中心的交互,关于不同模型下注册中心数据的变化,之前原理部分我们简单分析过。为更直观的对比服务模型变更带来的推送效率提升,我们来通过一个示例看一下不同模型注册中心的对比:对于 Spring Cloud 和 Kubernetes 模型,注册中心只会存储一条 DEMO - 10.210.134.30+metadata 的数据 对于老的 Dubbo 模型,注册中心存储了三条接口粒度的数据,分别对应三个接口 DemoService 1 2 3,并且很多的址数据都是重复的
四、应用级服务发现工作原理
4.1 设计原则
上面一节我们从服务模型及支撑大规模集群的角度分别给出了 Dubbo 往应用级服务发现靠拢的好处或原因,但这么做的同时接口粒度的服务治理能力还是要继续保留,这是 Dubbo 框架编程模型易用性、服务治理能力优势的基础。以下是我认为我们做服务模型迁移仍要坚持的设计原则:新的服务发现模型要实现对原有 Dubbo 消费端开发者的无感知迁移,即 Dubbo 继续面向 RPC 服务编程、面向 RPC 服务治理,做到对用户侧完全无感知 建立 Consumer 与 Provider 间的自动化 RPC 服务元数据协调机制,解决传统微服务模型无法同步 RPC 级接口配置的缺点
4.2 基本原理详解
应用级服务发现作为一种新的服务发现机制,和以前 Dubbo 基于 RPC 服务粒度的服务发现在核心流程上基本上是一致的:即服务提供者往注册中心注册地址信息,服务消费者从注册中心拉取&订阅地址信息。这里主要的不同有以下两点:4.2.1 注册中心数据以“应用 - 实例列表”格式组织,不再包含 RPC 服务信息"name": "provider-app-name",
"id": "192.168.0.102:20880",
"address": "192.168.0.102",
"port": 20880,
"sslPort": null,
"payload": {
"id": null,
"name": "provider-app-name",
"metadata": {
"metadataService": "{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}",
"endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"storage-type": "local",
"revision": "6785535733750099598",
}
},
"registrationTimeUTC": 1583461240877,
"serviceType": "DYNAMIC",
"uriSpec": null
}
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314"
]
一部分和实例相关的数据继续保留在注册中心,如 ip、port、机器标识等 另一部分和 RPC 方法相关的数据从注册中心移除,转而通过 MetadataService 暴露给消费端
服务提供者启动,首先解析应用定义的“普通服务”并依次注册为 RPC 服务,紧接着注册内建的 MetadataService 服务,最后打开 TCP 监听端口 启动完成后,将实例信息注册到注册中心(仅限 ip、port 等实例相关数据),提供者启动完成 服务消费者启动,首先依据其要“消费的 provider 应用名”到注册中心查询地址列表,并完成订阅(以实现后续地址变更自动通知) 消费端拿到地址列表后,紧接着对 MetadataService 发起调用,返回结果中包含了所有应用定义的“普通服务”及其相关配置信息 至此,消费者可以接收外部流量,并对提供者发起 Dubbo RPC 调用
4.3 服务自省中的关键机制
4.3.1 元数据同步机制Client 与 Server 间在收到地址推送后的配置同步是服务自省的关键环节,目前针对元数据同步有两种具体的可选方案,分别是:内建 MetadataService 独立的元数据中心,通过中细化的元数据集群协调数据
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="RPC Service 1" />
<dubbo:reference interface="RPC Service 2" />
<dubbo:reference interface="RPC Service N" />
<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:reference interface="RPC Service 1" provided-by="provider-app-x"/>
<dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />
<dubbo:reference interface="RPC Service N" provided-by="provider-app-y" />
五、总结与展望
应用级服务发现机制是 Dubbo 面向云原生走出的重要一步,它帮 Dubbo 打通了与其他微服务体系之间在地址发现层面的鸿沟,也成为 Dubbo 适配 Kubernetes Native Service 等基础设施的基础。我们期望 Dubbo 在新模型基础上,能继续保留在编程易用性、服务治理能力等方面强大的优势。但是我们也应该看到应用粒度的模型一方面带来了新的复杂性,需要我们继续去优化与增强;另一方面,除了地址存储与推送之外,应用粒度在帮助 Dubbo 选址层面也有进一步挖掘的潜力。Docker 禁止美国“实体清单”主体使用,Docker 开源项目不受影响一个数学家数了数小说中 20000 个字母,然后诞生了语言识别模型
美国如果把根域名服务器封了,中国会从网络上消失?“老鹰”被 AI 强化学习后,“小鸡”越来越少了?张东升,我知道是你!如何使用GAN做一个秃头生产器
觉得不错,请点个在看呀